﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Xml;

namespace VidoopSecure
{
    public class SmsotpService : Service
    {
        /// <summary>
        /// Create an <see cref="VidoopSecure.SmsotpService" /> instance.
        /// </summary>
        /// <param name="manager">The <see cref="VidoopSecure.VSManager" /> 
        /// for performing operations.</param>
        /// <param name="site">The <see cref="VidoopSecure.Site" /> associated
        /// with the service.</param>
        /// <param name="apiBase">The base URL for the VidoopSecure web service.</param>
        public SmsotpService(VSManager manager, Site site, string apiBase)
            : base(manager, site, apiBase)
        {
        }

        /// <summary>
        /// Create an instance of a <see cref="VidoopSecure.SmsOtp" />.
        /// </summary>
        /// <param name="userId">Identifier of user associated with the Smsotp.</param>
        /// <param name="phoneNumber">Phone number to which the message will be sent.</param>
        /// <returns>An instance of a <see cref="VidoopSecure.SmsOtp" />.</returns>
        public Smsotp NewSmsotp(string userId, string phoneNumber)
        {
            string apiUrl = this.CreateRequestUrl("/customers/" + this.Site.CustomerId +
                "/sites/" + this.Site.SiteName + "/services/smsotp");

            string credentials = this.Site.Username + Util.CREDENTIALS_SEPARATOR + this.Site.Password;

            Dictionary<string, string> parameters = new Dictionary<string, string>
            {
                { "user_id", userId },
                { "phone", phoneNumber }
            };

            HttpProxy proxy = this.Manager.ApiCall(apiUrl, "POST", parameters, credentials);

            if (proxy.StatusCode != (int)HttpStatus.Created)
            {
                int status = proxy.StatusCode;
                proxy.Close();
                throw new VidoopSecureException(status, "Failed to create and send a new Sms message.");
            }
            else
            {
                Smsotp smsotp = Smsotp.FromXml(proxy.Response.GetResponseStream());
                proxy.Close();
                return smsotp;
            }
        }

        /// <summary>
        /// Get an <see cref="VidoopSecure.SmsOtp" /> given an Id represented by
        /// <paramref name="smsotpId"/>.
        /// </summary>
        /// <param name="smsotpId">An SMS One Time Password Id.</param>
        /// <returns>An instance of <see cref="VidoopSecure.Smsotp" />.</returns>
        public Smsotp GetSmsotp(string smsotpId)
        {
            string apiUrl = this.CreateRequestUrl("/customers/" + this.Site.CustomerId +
                "/sites/" + this.Site.SiteName + "/services/smsotp/" + smsotpId);

            string credentials = this.Site.Username + Util.CREDENTIALS_SEPARATOR + this.Site.Password;

            HttpProxy proxy = this.Manager.ApiCall(apiUrl, "GET", null, credentials);
            if (proxy.StatusCode != (int)HttpStatus.OK)
            {
                int status = proxy.StatusCode;
                proxy.Close();
                throw new VidoopSecureException(status,
                    string.Format("Failed to get Sms transaction with Id = {0}", smsotpId));
            }
            else
            {
                Smsotp smsotp = Smsotp.FromXml(proxy.Response.GetResponseStream());
                proxy.Close();
                return smsotp;
            }
        }

        /// <summary>
        /// Validates whether <paramref name="code"/> is the correct code sent by this
        /// <see cref="VidoopSecure.Smsotp" />.
        /// </summary>
        /// <param name="smsotpId">An SMS One Time Password identifier.</param>
        /// <param name="code">The code to be validated.</param>
        /// <returns>true if <paramref name="code"/> is the correct code for the
        /// <see cref="VidoopSecure.Smsotp" /> identified by <paramref name="smsotpId"/>.
        /// </returns>
        public bool ValidateSmsotp(string smsotpId, string code)
        {
            string apiUrl = this.CreateRequestUrl("/customers/" + this.Site.CustomerId +
                "/sites/" + this.Site.SiteName + "/services/smsotp/" + smsotpId);

            string credentials = this.Site.Username + Util.CREDENTIALS_SEPARATOR + this.Site.Password;

            Dictionary<string, string> parameters = new Dictionary<string, string>
            {
                { "otp", code }
            };

            HttpProxy proxy = this.Manager.ApiCall(apiUrl, "POST", parameters, credentials);
            int status = proxy.StatusCode;

            switch (status)
            {
                case (int)HttpStatus.CannotRetry:
                    {
                        proxy.Close();
                        throw new VidoopSecureException(status,
                            "Authentication with this SMS has already been successful and cannot be attempted again.");
                    }

                case (int)HttpStatus.Gone:
                    {
                        proxy.Close();
                        throw new VidoopSecureException(status, "This SMS has expired.");
                    }

                case (int)HttpStatus.AuthenticationFailed:
                    {
                        proxy.Close();
                        throw new VidoopSecureException(status, "Authentication failed.");
                    }

                case (int)HttpStatus.OK:
                    {
                        proxy.Close();
                        break;
                    }

                default:
                    {
                        proxy.Close();
                        throw new VidoopSecureException(status, "Unexpected error");
                    }
            }

            return true;
        }
    }
}
